

#include <stdio.h>
#include "stm32l4xx_hal.h"
#include "tim.h"
#include "gpio.h"
#include "gpio_i2c_sht30.h"


#define I2C_CLK_STRETCH_TIMEOUT 50


//#define CONFIG_GPIO_I2C_DEBUG

#ifdef CONFIG_GPIO_I2C_DEBUG
#define i2c_print(format,args...) printf(format,##args)
#else
#define i2c_print(format,args...) do{} while(0)
#endif


typedef struct i2c_gpio_s
{
	GPIO_TypeDef		*group;
	uint16_t			scl;
	uint16_t			sda;

}i2c_gpio_t;

//PB13 SCL PB14 SDA
static i2c_gpio_t i2c_pins = { GPIOB, GPIO_PIN_13, GPIO_PIN_14};

#define SDA_IN()	do{ GPIO_InitTypeDef GPIO_InitStruct = {0}; \
						GPIO_InitStruct.Pin = i2c_pins.sda;\
						GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\
						GPIO_InitStruct.Pull = GPIO_PULLUP;\
						GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
						HAL_GPIO_Init(i2c_pins.group, &GPIO_InitStruct);\
					}while(0)

#define SDA_OUT()	do{ GPIO_InitTypeDef GPIO_InitStruct = {0}; \
						GPIO_InitStruct.Pin = i2c_pins.sda;\
						GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
						GPIO_InitStruct.Pull = GPIO_PULLUP;\
						GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
						HAL_GPIO_Init(i2c_pins.group, &GPIO_InitStruct);\
					}while(0)

#define SCL_OUT()	do{ GPIO_InitTypeDef GPIO_InitStruct = {0}; \
						GPIO_InitStruct.Pin = i2c_pins.scl;\
						GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
						GPIO_InitStruct.Pull = GPIO_PULLUP;\
						GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
						HAL_GPIO_Init(i2c_pins.group, &GPIO_InitStruct);\
					}while(0)

#define SCL_H()		HAL_GPIO_WritePin(i2c_pins.group, i2c_pins.scl, GPIO_PIN_SET)
#define SCL_L()		HAL_GPIO_WritePin(i2c_pins.group, i2c_pins.scl, GPIO_PIN_RESET)
#define SDA_H()		HAL_GPIO_WritePin(i2c_pins.group, i2c_pins.sda, GPIO_PIN_SET)
#define SDA_L()		HAL_GPIO_WritePin(i2c_pins.group, i2c_pins.sda, GPIO_PIN_RESET)


#define READ_SDA()	HAL_GPIO_ReadPin(i2c_pins.group, i2c_pins.sda)
#define READ_SCL()	HAL_GPIO_ReadPin(i2c_pins.group, i2c_pins.scl)

static inline uint8_t I2c_WaitWhileClockStretching(uint16_t timeout)
{
	while(timeout-- > 0)
	{
		if(READ_SCL())
			break;
		delay_us(1);
	}

	return timeout ? NO_ERROR : BUS_ERROR;
}

uint8_t I2c_StartCondition()
{
	uint8_t		rv = NO_ERROR;

	SDA_OUT();
	SCL_OUT();

	SDA_H();
	delay_us(1);
	SCL_H();
	delay_us(1);

#ifdef I2C_CLK_STRETCH_TIMEOUT
	rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
	if(rv)
	{
		i2c_print("ERROR: %s() I2C bus busy\n", __func__);  //当前函数名__func__
		return rv;
	}
#endif

	SDA_L();
	delay_us(2);

	SCL_L();
	delay_us(2);

	return rv;
}


uint8_t I2c_StopCondition(void)
{
	uint8_t		rv = NO_ERROR;

	SDA_OUT();

	SCL_L();
	SDA_L();
	delay_us(2);

	SCL_H();
	delay_us(2);

#ifdef I2C_CLK_STRETCH_TIMEOUT
	rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
	if(rv)
	{
		i2c_print("ERROR: %s() I2C bus busy\n", __func__);
	}
#endif
	SDA_H();
	delay_us(2);

	return rv;
}

uint8_t I2c_WriteByte(uint8_t byte)
{
	uint8_t		rv = NO_ERROR;
	uint8_t		mask;

	SDA_OUT();
	SCL_L();

	for(mask=0x80; mask>0; mask>>=1)
	{
		if((mask & byte) == 0)
			SDA_L();
		else
			SDA_H();

		delay_us(1);

		SCL_H();
		delay_us(5);

#ifdef I2C_CLK_STRETCH_TIMEOUT
		rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
		if(rv)
		{
			i2c_print("ERROR: %s() I2C bus busy\n", __func__);
			goto OUT;
		}
#endif

		SCL_L();
		delay_us(1);  //data hold time(t_HD;DAT)
	}

	/*clk #9 wait ACK/NAK from slave*/
	SDA_IN();
	SCL_H();  //CLK#9 FOR ACK
	delay_us(1); //data set-up time

#ifdef I2C_CLK_STRETCH_TIMROUT
	rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
	if(rv)
	{
		i2c_print("ERROR: %s() I2C bus busy\n", __func__);
		goto OUT;
	}
#endif

	/*HIGH level means NAK*/
	if(READ_SDA())
		rv = ACK_ERROR;
	OUT:
	SCL_L();
	delay_us(20);

	return rv;
}

uint8_t I2c_ReadByte(uint8_t *byte, uint8_t ack)
{
	uint8_t		rv = NO_ERROR;
	uint8_t		mask;

	*byte = 0x00;

	SDA_IN();

	/*1BYTE=8BIT, MSB send : bit[7]-->bit[0]*/
	for(mask = 0x80; mask > 0; mask >>= 1)
	{
		SCL_H();		//start clock on SCL-LINE
		delay_us(1);  //clock set-up time

#ifdef I2C_CLK_STRETCH_TIMEOUT
		rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
		if(rv)
		{
			i2c_print("ERROR: %s() I2C bus busy\n", __func__);
			goto OUT;
		}
#endif

		if(READ_SDA())
			*byte |= mask; //read bit

		SCL_L();
		delay_us(1); //data hold time
	}

	/* clk #9 send ACK/NAK to slave */
	if(ack == ACK)
	{
		SDA_OUT();
		SDA_L();  //send Acknowledge if necessary
	}
	else if(ack == NAK)
	{
		SDA_OUT();
		SDA_H();
	}

	delay_us(1);
	SCL_H();
	delay_us(2);

#ifdef I2C_CLK_STRETCH_TIMEOUT
		rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
		if(rv)
		{
			i2c_print("ERROR: %s() I2C bus busy\n", __func__);
		}
#endif

		OUT:

		SCL_L();
		delay_us(2);

		return rv;

}


uint8_t I2c_SendAddress(uint8_t addr)
{
	return I2c_WriteByte(addr);
}


int I2C_Master_Receive(uint8_t addr, uint8_t *buf, int len)
{
	int		i;
	int		rv = NO_ERROR;
	uint8_t	byte;

	I2c_StartCondition();

	rv = I2c_SendAddress(addr);

	if(rv)
	{
		i2c_print("Send I2C read address failure, rv = %d\n", rv);
		goto OUT;
	}

#ifdef I2C_CLK_STRETCH_TIMEOUT
		rv = I2c_WaitWhileClockStretching(I2C_CLK_STRETCH_TIMEOUT);
		if(rv)
		{
			i2c_print("ERROR: %s() I2C wait clock stretching failure, rv = %d\n", __func__, rv);
			return rv;
		}
#endif

		for(i=0; i<len; i++)
		{
			if(!I2c_ReadByte(&byte, ACK))
				buf[i] = byte;
			else
				goto OUT;
		}

		OUT:
		I2c_StopCondition();
		return rv;
}

int I2C_Master_Transmit(uint8_t addr, uint8_t *data, int bytes)
{
	int		i;
	int		rv = NO_ERROR;

	if(!data)
	{
		return PARM_ERROR;
	}

	i2c_print("I2C Master start transimit [%d] bytes data to addr [0x%02x]\n", bytes, addr);
	I2c_StartCondition();

	rv = I2c_SendAddress(addr);
	if(rv)
	{
		goto OUT;
	}

	for(i=0; i<bytes; i++)
	{
		if(NO_ERROR != (rv=I2c_WriteByte(data[i])))
		{
			break;
		}
	}

	OUT:

	I2c_StopCondition();
	return rv;
}








/*
 * gpio_i2c_sht30.c
 *
 *  Created on: Aug 20, 2021
 *      Author: dell
 */


